// CSE571 - dealer-main.cpp          
// Authors: Jonathan Wald, Daniel Sarfati, Guangle Fan
// This file holds the main function that is run by the server program.

#include <iostream>
#include "stdio.h"
#include <map>
#include <iterator>
#include <utility>
#include <ctime>

#include "ace/Auto_Ptr.h"
#include "ace/INET_Addr.h"
#include "ace/SOCK_Acceptor.h"
#include "ace/SOCK_Stream.h"
#include "ace/Signal.h"

#include "dealer.h"
#include "game.h"
#include "player.h"
#include "signal-handler.h"
#include "sig-timer-handler.h"
#include "io-manager.h"
#include "globals.h"
#include "msg-flag.h"
#include "server-interpreter.h"

class DealerSvcHandler;

typedef ACE_Acceptor<DealerSvcHandler,ACE_SOCK_ACCEPTOR> DealerAcceptor; 

const static int DEALER_DEFAULT_PORT = 8000;

int main(int argc, char* argv[]) {
   int port = DEALER_DEFAULT_PORT;
   string dealer_name;
   
   const int NAME_FLAG = 0, PORT_FLAG = 1;
   int flag;
  
   bool parse_error = false;
   string error_msg;
     
   // Parse command line arguments.
   for(int i = 1; i < argc; i+=2) {
      if (!strcmp("-n", argv[i])) flag = NAME_FLAG;
      else if (!strcmp("-p", argv[i])) flag = PORT_FLAG;
      else {
         parse_error = true;
         error_msg = "Unknown flag.";
         break;
      }
      
      if ((i+1) == argc) {     // this means we don't have an even number of tokens -> parameter or flag must be missing
         parse_error = true;
         error_msg = "Missing parameter or flag.";
         break;
      }
      
      if ((argv[i+1][0] == '-') || (strlen(argv[i+1]) == 0)) {
         parse_error = true;
         error_msg = "Missing parameter for flag.";
         break;
      }
      
      switch (flag) {
         case NAME_FLAG:
            dealer_name = argv[i+1];
            break;
         case PORT_FLAG:
            port = atoi(argv[i+1]);
            break;
      }
   }
   
   if (dealer_name.size() == 0) {
      parse_error = true;
      error_msg = "Dealer must have a name.";
   }
   else Dealer::instance()->name = dealer_name;
   
   if (parse_error) {
      std::cout << "ERROR: " << error_msg << std::endl;
      std::cout << "Usage: ./server -n <dealer name> [-p <server port>]" << std::endl;
      return -1;
   }
   
   std::cout << "Dealer's name: " << Dealer::instance()->name << std::endl; 
   srand(time(NULL));
   
   // Attempt to set up a socket for Dealer to listen on
   const int HOST_NAME_SIZE = 64;
   ACE_INET_Addr server_addr;
   char address_string [HOST_NAME_SIZE];
   ::gethostname (address_string, HOST_NAME_SIZE - 1);
   if (server_addr.set(port, address_string) == -1) {
      std::cout << "Unable to set server address:" << address_string << std::endl;
      return -1;
   }
   
   server_addr.addr_to_string (address_string, HOST_NAME_SIZE - 1);
   std::cout << "Address and port: " << address_string << std::endl;
   
   DealerAcceptor dealer_acceptor;
   if (dealer_acceptor.open(server_addr, ACE_Reactor::instance()) == -1) {
     std::cout << "Address is already in use by another server." << std::endl;
     return -1;
   }
   
   // Implement signal handler.
   SigHandler sh (ACE_Reactor::instance());
   // Implement timer to send quit messages.
   DealerSigTimerHandler dst (ACE_Reactor::instance());
   
   IOManager* io_manager = IOManager::instance();
   io_manager->open();

   Dealer::instance()->interpreter.activate(THR_NEW_LWP |
					    THR_DETACHED, 1);

   while(!SigHandler::sigint_fired() || !IOManager::instance()->shut_down) {
     ACE_Reactor::instance()->handle_events();
   }

   // Stay open for several seconds so that client can process termination.
   sleep(2);

   if (Dealer::instance() != NULL) {
     delete Dealer::instance();
   }
   
   return 0;
}
